#pragma once

#include <vector>
#include <iosfwd>
#include <string>
#include "basetypes.h"

class GreatUInt;
//class FastInt;

class FastUInt
{
public:
	//ctors and copy
	explicit FastUInt(const UInt i_num = 0);
	explicit FastUInt(const char* i_string);
	explicit FastUInt(const std::string& i_string);
	explicit FastUInt(const GreatUInt& i_that);
	FastUInt(const UInt i_num, const size_t i_reservation);
	FastUInt(const FastUInt& i_that);
	FastUInt& operator=(const FastUInt& i_that);
	FastUInt& operator=(const UInt i_num);

	//Accessors
	UInt ToUInt() const;
	void ToGreatUInt(GreatUInt& o_greatUInt) const;
	void ToString(std::string& o_string)  const;
	//void ToFastInt(FastInt& o_fastInt) const;
	bool IsZero() const;
	bool IsUInt() const;
	bool IsLessThan(const FastUInt& i_that) const;
	UInt GetNumDigits() const; //inefficient
	UInt GetDigit(const UInt i_digitNum) const; //inefficient
	UInt DigitSum() const; //inefficient

	//modifiers
	FastUInt& Assign(const UInt i_num);
	FastUInt& Assign(const char* i_string); //inefficient
	FastUInt& Assign(const std::string& i_string); //inefficient
	FastUInt& Assign(const GreatUInt& i_greatUInt);
	FastUInt operator++(int);
	FastUInt operator--(int);
	FastUInt& operator++();
	FastUInt& operator--();
	FastUInt& operator+=(const FastUInt& i_that);
	FastUInt& operator+=(const UInt i_num);
	FastUInt& operator-=(const FastUInt& i_that);
	FastUInt& operator-=(const UInt i_num);
	FastUInt& operator*=(const FastUInt& i_that);
	FastUInt& operator*=(const UInt i_factor);
	FastUInt& operator/=(const FastUInt& i_that);
	FastUInt& operator%=(const FastUInt& i_that);
	FastUInt& operator%=(const UInt i_that);
	FastUInt& operator&=(const FastUInt& i_that);
	FastUInt& operator|=(const FastUInt& i_that);
	FastUInt& operator^=(const FastUInt& i_that);
	FastUInt& operator<<=(const UInt i_factor);
	FastUInt& operator>>=(const UInt i_factor);
	FastUInt& ApplyExp(const UInt i_exp);
	FastUInt& SetZero();
	FastUInt& SetOne();
	void Swap(FastUInt& i_that);

	// Arguments are read-only operands, result is saved in *this.
	FastUInt& Add(const FastUInt& i_first, const FastUInt& i_second);
	FastUInt& Sub(const FastUInt& i_first, const FastUInt& i_second);
	FastUInt& Mul(const FastUInt& i_first, const FastUInt& i_second);
	FastUInt& BitAnd(const FastUInt& i_first, const FastUInt& i_second);
	FastUInt& BitOr(const FastUInt& i_first, const FastUInt& i_second);
	FastUInt& BitXor(const FastUInt& i_first, const FastUInt& i_second);
	FastUInt& DivWithRem(const FastUInt& i_toBeDivided, const FastUInt& i_divisor, bool i_storeQuotient = true, FastUInt* o_other = 0);

	//friends
	friend UInt operator%(const FastUInt& i_FastUInt, UInt i_factor);
	friend bool operator==(const FastUInt& i_left, const FastUInt& i_right);
	friend bool operator!=(const FastUInt& i_left, const FastUInt& i_right);
	friend Int Compare(const FastUInt& i_left, const FastUInt& i_right);

private:
	typedef std::vector<UInt> Container;
	Container m_data;
};


//non members
const FastUInt operator+(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt operator-(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt operator*(const FastUInt& i_FastUInt, UInt i_factor);
const FastUInt operator*(UInt i_factor, const FastUInt& i_FastUInt);
const FastUInt operator*(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt operator/(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt operator%(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt operator&(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt operator|(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt operator^(const FastUInt& i_left, const FastUInt& i_right);
bool operator<(const FastUInt& i_left, const FastUInt& i_right);
bool operator<=(const FastUInt& i_left, const FastUInt& i_right);
bool operator>(const FastUInt& i_left, const FastUInt& i_right);
bool operator>=(const FastUInt& i_left, const FastUInt& i_right);
const FastUInt Exp(const FastUInt& i_base, const UInt i_exp);

std::ostream& operator<<(std::ostream& os, const FastUInt& i_data);

//friends
UInt operator%(const FastUInt& i_FastUInt, UInt i_factor);
bool operator==(const FastUInt& i_left, const FastUInt& i_right);
bool operator!=(const FastUInt& i_left, const FastUInt& i_right);

// <0 first is greater, ==0 are equal, >0 second is greater
Int Compare(const FastUInt& i_left, const FastUInt& i_right); 

#include "FastUInt.inl"